from flask import request, jsonify, session
from aps import app
from aps.models.atributo import *
from aps.models.tipoitem import *
from aps.models.item import *
from aps.models.itematributovalor import *
from aps.models.tipoitematributo import *
from aps.models.relacion import *
from aps.models.uploadedfile import *
from aps.models.usuario import *
from aps.views.historial import *

@app.route('/crear_atributo', methods=['GET', 'POST'])  
def crear_atributo():
    """
    Nos permite traer los parametros que fueron cargados por el usuario
    y guardarlos en la base de datos.
    @param request: objeto que encapsula la peticion del cliente
    @return : True si la accion se realizo correctamente
    """     
    nombre   = request.form['nombre']
    tipodato = request.form['tipodato']
    valordef = request.form['valordef']
    # se agrega a la BD
    model    = Atributo(nombre, tipodato, valordef)
    bdsession.add(model)
    return jsonify ({'success' : True})

@app.route('/modificar_atributo', methods=['GET', 'POST'])  
def modificar_atributo():
    """
    Nos permite traer los parametros que fueron modificados por el usuario
    y guardar los cambios en la base de datos.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """ 
    id       = request.form['id']
    nombre   = request.form['nombre']
    tipodato = request.form['tipodato']
    valordef = request.form['valordef']
    # Se modifica en la BD
    model    = Atributo(nombre,tipodato,valordef)
    model.id = id
    bdsession.merge(model)  
    return jsonify ({'success':True})

@app.route('/eliminar_atributo', methods=['GET', 'POST'])  
def eliminar_atributo():
    """
    Nos permite traer el id del atributo a eliminar, eliminar las dependendcias
    del mismo con respecto a otras tablas y eliminar el registro de la base de datos.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente y False en caso contrario
    """ 
    id       = request.form['id']
    atributo = bdsession.query(Atributo).filter_by(id=id).first()
    if atributo is None:
        return jsonify ({'success':False})
    bdsession.delete(atributo)
    return jsonify ({'success' : True})

@app.route('/consultar_atributo', methods=['GET', 'POST'])  
def consultar_atributo():
    """
    Nos permite traer los parametros de consulta(el filtro y el valor) y mostrar
    los atributos que cumplen con la condicion del filtro.
    @param request: objeto que encapsula la peticion del cliente
    @return: si la accion se realizo correctamente
    """ 
    atributos = None
    if request.args.has_key('filtro'):
        filtro    = request.args['filtro']
        valor     = request.args['valor']
        sentencia = 'SELECT * from Atributo WHERE {0}=\'{1}\''.format(filtro,valor)
        atributos = bdsession.query(Atributo).from_statement(sentencia).all()
    else:
        atributos = bdsession.query(Atributo).all()
    
    data = []
    for atributo in atributos:
        if atributo.id > 4:
            item = {}
            item['id']       = atributo.id
            item['nombre']   = atributo.nombre
            item['tipodato'] = atributo.tipodato
            item['valordef'] = atributo.valordef
            data.append(item)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/consulta_asignar_atributos', methods=['GET', 'POST'])  
def consulta_asignar_atributos():
    """
    Nos permite traer todos los atributos asignados y asignables a un tipoitem
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente, la lista de atributos asignados al tipoitem y la lista de atributos asignables al tipoitem
    """
    def process_atributo_list(list):
        """
        Serializa una lista de con los datos de los atributos para enviarla al cliente
        @param list: lista de objectos Atributo obtenidas desde la BD
        @return: result lista procesada de atributos
        """ 
        result = []
        for atributo in list:
            if atributo.id > 4:
                item = [None,None,None,None]
                item[0] = atributo.id
                item[1] = atributo.nombre
                item[2] = atributo.tipodato
                item[3] = atributo.valordef
                result.append(item)
        return result
    
    id_tipoitem = request.form['id']
    # Obtenemos la lista de atributos que fueron asignados al tipoitem
    # Atributos es de tipo TipoitemAtributo[] por tanto es necesario extraer el 'atributo' de la relacion
    atributos_asignados  = [x.atributo for x in bdsession.query(Tipoitem).filter_by(id=id_tipoitem).first().atributos]
    # Obtenemos la lista de atributos que no fueron asignados al tipoitem
    atributos_asignables = bdsession.query(Atributo).from_statement('select * from Atributo where id not in (select idatributo from TipoitemAtributo where idtipoitem=\'{0}\')'.format(id_tipoitem)).all()
    
    asignados  = process_atributo_list(atributos_asignados)
    asignables = process_atributo_list(atributos_asignables)

    return jsonify ({'success':True, 'asignados':asignados, 'asignables':asignables})


@app.route('/asignar_desasignar_atributo', methods=['GET', 'POST'])  
def asignar_desasignar_atributo():
    """
    Nos permite asignar/desasignar atributos a un tipoitem
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    received    = eval(request.form['data'])
    # id del tipo de item a asignar/desasignar atributos
    id_tipoitem = received['id_tipoitem']
    # ids de atributos asignados
    data   = received['data']

    # obtenemos el tipo de item desde la BD
    tipoitem   = bdsession.query(Tipoitem).filter_by(id=id_tipoitem).first()
    # eliminamos sus atributos asignados anteriormente
#     aux = None
#     aux = bdsession.query(TipoitemAtributo).filter_by(idtipoitem=id_tipoitem).all()#synchronize_session=False
#     if aux is not None:
    bdsession.query(TipoitemAtributo).filter_by(idtipoitem=id_tipoitem).delete()#

    # actualizamos el tipoitem
    bdsession.refresh(tipoitem)
    # asignamos los atributos base
    tipoitem.atributos.append(TipoitemAtributo(id_tipoitem, 1))
    tipoitem.atributos.append(TipoitemAtributo(id_tipoitem, 2))
    tipoitem.atributos.append(TipoitemAtributo(id_tipoitem, 3))
    tipoitem.atributos.append(TipoitemAtributo(id_tipoitem, 4))
    # creamos una nueva lista de atributos asignados
    for id_atributo in data:
        tipoitem.atributos.append(TipoitemAtributo(id_tipoitem, id_atributo))
    # guardamos los cambios
    bdsession.merge(tipoitem)
    items = None
    # Buscamos si es que existen los items que utilizen este tipo de item para agregarle el nuevo atributo
    items = bdsession.query(Item).filter_by(idtipoitem=id_tipoitem).all()
    # Si es que exiten items con ese tipo de item creamos una nueva version del item con el nuevo atributo
    if len(items) != 0:
        # Creamos la nueva version por cada item    
        for it in items:
            # Actualizacion de los atributos base del item
            numfase      = it.numfase
            nombre       = it.nombre
            descripcion  = it.descripcion
            prioridad    = it.prioridad
            complejidad  = it.complejidad
            version      = it.version + 1
            estado       = it.estado
            id_lineabase = it.idlineabase
            id_tipoitem  = it.idtipoitem
            id_fase      = it.idfase
            id_item = it.id
            # Actualizamos el item en la BD
            model    = Item(numfase, nombre, descripcion, version, prioridad, complejidad, estado, id_lineabase, id_tipoitem, id_fase)
            model.id = id_item
            bdsession.merge(model)
            bdsession.flush()
            
            # Recuperamos el item modificado
            item = bdsession.query(Item).filter_by(id=id_item).first()
        
            # traemos los valores de los atributos son de la version anterior
            sentencia= 'SELECT * from ItemAtributoValor WHERE iditem={0} and version={1}'.format(id_item ,version-1) 
            itav = bdsession.query(ItemAtributoValor).from_statement(sentencia).all()
            # guardamos los valores de los atributos para esta version
            for i in itav:
                attr = bdsession.query(Atributo).filter_by(id=i.idatributo).first()
                if attr.tipodato == u'ARCHIVO':
                    uf = bdsession.query(UploadedFile).filter_by(iditem=id_item,idatributo=i.idatributo,filename=i.valor,version=version-1).first()
                    model1 = UploadedFile(uf.iditem,uf.idatributo,uf.filename,uf.data,uf.size,version)
                    bdsession.add(model1)
                item.valoratributo_x_version.append(ItemAtributoValor(id_item,i.idatributo,version,i.valor))        
            iav = None    
            for a in tipoitem.atributos:
                iav = bdsession.query(ItemAtributoValor).filter_by(iditem=it.id,idatributo=a.atributo.id).all()
                if len(iav) == 0:
                    valor = bdsession.query(Atributo).filter_by(id=a.atributo.id).first().valordef
                    item_valor = ItemAtributoValor(it.id, a.atributo.id, version, valor)
                    item.valoratributo_x_version.append(item_valor)
                    bdsession.merge(item) 
                iav = None
                
            # Obtenemos las relaciones del item y creamos un solo conjunto de relaciones
            relaciones   = []
            item.version = item.version - 1
            for x in it.get_antecesores('ALL')['validas']:
                relaciones.append(x)
            for x in it.get_sucesores('ALL')['validas']:
                relaciones.append(x)
            item.version = item.version + 1
            # Actualizamos las relaciones
            for r in relaciones:
                vorigen  = r.vorigen+1  if int(r.idorigen) == int(it.id) else r.vorigen
                vdestino = r.vdestino+1 if int(r.iddestino) == int(it.id) else r.vdestino
                model2   = Relacion(r.idorigen, r.iddestino, vorigen, vdestino, r.tipo, r.estado)
                bdsession.add(model2) 
                
            # Creamos una entrada en el historial
            log_it(item.id,session['usuario'],'item modificado dentro del proyecto se agregaron nuevos atributos, la version actual es ' + str(version) + ', estado : ' + str(estado)) 
    
    return jsonify ({'success':True})

@app.route('/consulta_atributo_x_tipoitem', methods=['GET', 'POST'])  
def consulta_atributo_x_tipoitem():
    """
    Nos permite obtener la lista detallada de atributos asignados a un tipo de item
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    id_tipoitem = request.args['id_tipoitem']
    tipoitem    = bdsession.query(Tipoitem).filter_by(id=id_tipoitem).first()
    data = []
    for atributo in tipoitem.atributos:
        item = {}
        item['id']       = atributo.atributo.id
        item['nombre']   = atributo.atributo.nombre
        item['tipodato'] = atributo.atributo.tipodato
        item['valordef'] = atributo.atributo.valordef
        data.append(item)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/consulta_atributo_x_item', methods=['GET', 'POST'])  
def consulta_atributo_x_item():
    """
    Nos permite obtener la lista detallada de atributos asignados a un item
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    atributos = None
    id_item = request.args['id_item']
    if not request.args.has_key('version'):
        item    = bdsession.query(Item).filter_by(id=id_item).first()
        sentencia= 'SELECT * from Itematributovalor WHERE iditem=\'{0}\' and version=\'{1}\''.format(id_item,item.version) 
        atributos = bdsession.query(ItemAtributoValor).from_statement(sentencia).all()
    else:
        version = request.args['version']
        item    = bdsession.query(Item).filter_by(id=id_item).first()
        sentencia= 'SELECT * from Itematributovalor WHERE iditem=\'{0}\' and version=\'{1}\''.format(id_item,version) 
        atributos = bdsession.query(ItemAtributoValor).from_statement(sentencia).all()    
    data = []
    for atributo in atributos:
        item = {}
        item['id']       = atributo.idatributo
        item['nombre']   = bdsession.query(Atributo).filter_by(id=atributo.idatributo).first().nombre
        item['tipodato'] = bdsession.query(Atributo).filter_by(id=atributo.idatributo).first().tipodato
        if item['tipodato'] == u'ARCHIVO' and atributo.valor != bdsession.query(Atributo).filter_by(id=atributo.idatributo).first().valordef:
            link = 'download_file?i={0}&a={1}&v={2}&f={3}'.format(id_item, atributo.idatributo, version, atributo.valor)
            item['valordef'] = '<a href=\"' + link + '\">' + atributo.valor + '</a>'
        else:
            item['valordef'] = atributo.valor
        data.append(item)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/desasignar_atributo', methods=['GET', 'POST'])  
def desasignar_atributo():
    """
    Nos permite saber si ya existe un item que utilice este tipo de item
    @return: True si la accion se realizo correctamente
    """
    print 'holaaaaaaaaaaaa'
    id_tipoitem = request.form['id']
    # Buscamos si es que existen los items que utilizen este tipo de item para agregarle el nuevo atributo
    items = bdsession.query(Item).filter_by(idtipoitem=id_tipoitem).all()
    # Si es que exiten items con ese tipo de item creamos una nueva version del item con el nuevo atributo
    if len(items) != 0:
        return jsonify ({'success':False})
    else:
        return jsonify ({'success':True})
